package cn.lg.soar.mvc.config;

import cn.lg.soar.common.algorithm.serial.Snowflake;
import cn.lg.soar.common.constant.MDCKey;
import cn.lg.soar.common.data.Soar64;
import cn.lg.soar.common.model.CurrentThreadContextInfo;
import cn.lg.soar.common.util.current.*;
import cn.lg.soar.mvc.util.ServletUtils;
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.MDC;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;

import java.io.IOException;
import java.util.HashSet;
import java.util.Set;

/**
 * 当前用户过滤器（主要拥于清除当前用户，释放内存）
 * @author luguoxiang
 * 开源项目：https://gitee.com/lgx1992/lg-soar 求star！请给我star！请帮我点个star！
 */
@Configuration
public class CurrentUserHolderConfig {

    private final static Set<ThreadLocal<?>> THREAD_LOCALS = new HashSet<>();

    @Bean
    public FilterRegistrationBean<Filter> currentUserHolderFilterBean() {
        FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>();
        registration.setFilter(new HandlerFilter());
        registration.addUrlPatterns("/*");
        registration.setName("currentUserHolderFilter");
        registration.setOrder(Ordered.HIGHEST_PRECEDENCE + 10);
        return registration;
    }

    public static class HandlerFilter implements Filter {
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            // 强转为 HttpServletRequest
            HttpServletRequest request = (HttpServletRequest) servletRequest;
            String requestId = request.getHeader(MDCKey.TRACE_ID);
            if (requestId == null) {
                requestId = Soar64.ofLong(Snowflake.nextValue());
            }
            ((HttpServletResponse) servletResponse).addHeader(MDCKey.TRACE_ID, requestId);
            MDC.put(MDCKey.TRACE_ID, requestId);
            filterChain.doFilter(servletRequest, servletResponse);
            MDC.remove(MDCKey.TRACE_ID);
            // 清除ThreadLocal，释放内存
            ThreadLocalHolder.removeCurrentUser();
            ThreadContext.clear();
            THREAD_LOCALS.forEach(ThreadLocal::remove);
        }
    }

    static {
        // 获取当前用户
        ThreadLocalHolder.setCurrentUserThreadLocal(ThreadLocal.withInitial(() -> {
            if (ServletUtils.isServletContext()) {
                HttpServletRequest request = ServletUtils.getRequest();
                String userInfo = request.getHeader(ICurrentUser.USER_KEY);
                if (userInfo != null) {
                    return CurrentTokenInfo.valueOf(userInfo);
                }
                Object data = request.getAttribute(ICurrentUser.USER_KEY);
                if (data == null) {
                    return null;
                }
                return (ICurrentUser) data;
            }
            return null;
        }));
        // 获取资源
        ThreadLocalHolder.setResourceThreadLocal(ThreadLocal.withInitial(() -> {
            if (ServletUtils.isServletContext()) {
                HttpServletRequest request = ServletUtils.getRequest();
                ICurrentUser user = UserContext.getUserNullable();
                Integer tenantId = 0;
                if (user == null) {
                    String tenantStr = request.getHeader("tenant-id");
                    if (tenantStr != null) {
                        tenantId = Integer.parseInt(tenantStr);
                    }
                } else {
                    tenantId = user.getCurrentTenantId();
                }
                return new CurrentThreadContextInfo(
                        request.getMethod().toUpperCase() + request.getServletPath(),
                        tenantId
                );
            }
            return new CurrentThreadContextInfo(null, 0);
        }));
    }

}
